#!/bin/bash
#
# #######################################################################################
#
# Copyright 2006 Jansen Sena <jansen@comunidadesol.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# #######################################################################################
#
# Script: mkdnsmap4me.sh
# Description: this script can help you to make larges DNS map files. You just need to 
#              provide informations like the IP prefix to use, two files listing 
#              hostnames to use with the servers and the clients and the first IP host 
#              portion to servers and clients.
#
# Syntax:
# 
# makednsmap4me.sh <IP prefix> <domain> \
#                  <servers file> <1st host IP suffix> <number of servers> \
#                  <clients file> <1st host IP suffix> <number of clients> \
#                  [ <printers file> <1st printer IP suffix> <number of printers> ]
#
# #######################################################################################

#
MSG_SYNTAX="makednsmap4me.sh <IP prefix> <domain> <servers file> <1st host IP suffix> <number of servers> [ <clients file> <1st host IP suffix> <number of clients> [ <printers file> <1st printer IP suffix> <number of printers> ]]"
#
# ###########################
# System utilities 
# ###########################
#
# PS: To be sure that all of the system utilities are presents in the ALL_UTILS variable
#
ALL_UTILS="CAT GREP BC ECHO DATE WC CUT SORT UNIQ"
CAT=/bin/cat
GREP=/bin/grep
BC=/usr/bin/bc
ECHO=/bin/echo
DATE=/bin/date
WC=/usr/bin/wc
CUT=/usr/bin/cut
SORT=/usr/bin/sort
UNIQ=/usr/bin/uniq
MV=/bin/mv
#
# Checking if all the system utilities are present
#
for util in $ALL_UTILS ; do 
    eval util_path=\$$util
    if [ ! -x $util_path ] ; then 
	$ECHO "The $util_path system utility defined in the $util doesn't exist in your system or"
	$ECHO "it isn't executable. Maybe you can solve this problem editing the utilities"
	$ECHO "variables in the $0 script."
	$ECHO "Aborting."
	exit 3
    fi
done
# 
# Verify number of parameters
#
if [ $# -ne 5 -a $# -ne 8 -a $# -ne 11 ] ; then 
    $ECHO "Invalid number of parameters."
    $ECHO "Syntax: $MSG_SYNTAX"
    exit 1
fi
#
HOSTS_TYPES=(SERVER)
HOSTS_TYPES_NUMBER=${#HOSTS_TYPES[*]} 
TODAY=`$DATE +%Y%m%d00`
IP_PREFIX=$1
DOMAIN=$2
SERVER_FILE=$3
SERVER_FIRST_IP_SUFFIX=$4
SERVER_NUMBER=$5
#
if [ $# -gt 5 ] ; then 
    CLIENT_FILE=$6
    CLIENT_FIRST_IP_SUFFIX=$7
    CLIENT_NUMBER=$8
    HOSTS_TYPES[$HOSTS_TYPES_NUMBER]="CLIENT"
    HOSTS_TYPES_NUMBER=${#HOSTS_TYPES[*]}
    #
    if [ $# -eq 11 ] ; then 
	PRINTER_FILE=$9
	shift 1
	PRINTER_FIRST_IP_SUFFIX=$9
	shift 1
	PRINTER_NUMBER=$9
	HOSTS_TYPES[$HOSTS_TYPES_NUMBER]="PRINTER"
	HOSTS_TYPES_NUMBER=${#HOSTS_TYPES[*]}
    fi
fi
#
# Checking the IP address prefix
#
OCT_1=`$ECHO $IP_PREFIX | $CUT -d. -f1`
OCT_2=`$ECHO $IP_PREFIX | $CUT -d. -f2`
OCT_3=`$ECHO $IP_PREFIX | $CUT -d. -f3`
OCT_REST=`$ECHO $IP_PREFIX | $CUT -d. -f4-`
#
for num in 1 2 3 ; do 
    eval oct="\$OCT_$num"
    if [ -z $oct ] ; then 
	$ECHO "Your IP address prefix doesn't have three octets."
	$ECHO "Aborting."
	exit 4
    fi
    if [ $oct -gt 255 ] ; then
	$ECHO "Your IP address prefix is invalid."
	$ECHO "The $[num]th part, $oct, is out of range."
	$ECHO "Aborting."
	exit 4
    fi 
done
if [ ! -z $OCT_REST ] ; then
    $ECHO "Your IP address prefix has more than three octets."
    $ECHO "Aborting."
    exit 4
fi
#
# Checking if the output files are already present in the system
# PS: if these files are already present in the system, mkdnsmap4me
#     will rename them using the ".old" suffix.
#
OUTPUT_FILE_DNSMAP="db.$DOMAIN"
OUTPUT_FILE_DNSREVMAP="db.$IP_PREFIX"
OUTPUT_FILE_NAMEDCONF="named.conf-$DOMAIN"
OUTPUT_FILES="OUTPUT_FILE_DNSMAP OUTPUT_FILE_DNSREVMAP OUTPUT_FILE_NAMEDCONF"
#
for file in $OUTPUT_FILES ; do 
    eval file_aux=\$$file
    if [ -f $file_aux ] ; then 
	$ECHO "Renaming $file_aux to $file_aux.old"
	$MV $file_aux $file_aux.old
	if [ $? -ne 0 ] ; then 
	    $ECHO "There was some problems to rename the $file_aux file."
	    $ECHO "Please, check this and run the script again."
	    $ECHO "Aborting."
	    exit 9
	fi
    fi
done
# #####################################################################
# Making some integrity checking tests before create the DNS map data
# #####################################################################
#
HOSTS_FILES=""
for (( hosttype_index=0; hosttype_index < HOSTS_TYPES_NUMBER; hosttype_index++)) ; do

    hosttype=${HOSTS_TYPES[$hosttype_index]}
    eval FILE=\$${hosttype}_FILE

    if [ ! -f $FILE ] ; then 
	$ECHO "$FILE file for $hosttype type doesn't exist in your system."
	$ECHO "Solve this problem and run $0 again."
	$ECHO "Aborting."
	exit 8
    fi

    # Get the host name file to check after if there are repeated names
    HOSTS_FILES="$HOSTS_FILES $FILE"
    
done
#
# Check if there is any repeated name in the host name files
#
HOSTNAMES_TOTAL_NUMBER=`$CAT $HOSTS_FILES | $GREP -v '^ *#.*' | $GREP -v '^ *$' | $WC -l`
HOSTNAMES_UNIQ_TOTAL_NUMBER=`$CAT $HOSTS_FILES | $GREP -v '^ *#.*' | $GREP -v '^ *$' | $SORT | $UNIQ | $WC -l`
#
if [ $HOSTNAMES_TOTAL_NUMBER -ne $HOSTNAMES_UNIQ_TOTAL_NUMBER ] ; then 
    $ECHO "You have repeated names in these files:$HOSTS_FILES."
    $ECHO "Aborting."
    exit 6
fi
#
for (( hosttype_index=0; hosttype_index < HOSTS_TYPES_NUMBER; hosttype_index++)) ; do
    hosttype=${HOSTS_TYPES[$hosttype_index]}
    eval FILE=\$${hosttype}_FILE
    eval FIRST_IP_SUFFIX=\$${hosttype}_FIRST_IP_SUFFIX
    eval NUMBER=\$${hosttype}_NUMBER
    
    # Check if the file including hosts names exists in the system
    if [ ! -f $FILE ] ; then
	$ECHO "$FILE file for $hosttype type doesn't exist."
	$ECHO "Aborting."
        exit 3
    fi

    # Max IP suffix for the valid hosts
    MAX_NUMBER=`$ECHO "$FIRST_IP_SUFFIX + $NUMBER - 1" | $BC`          

    # Hosts names (without comments and blank lines)
    HOSTS_NAMES=`$GREP -v '^ *#.*' $FILE | $GREP -v '^ *$'`              

    # Number of hosts in the file
    HOSTS_NAMES_NUMBER=`$ECHO $HOSTS_NAMES | $WC -w | $CUT -d" " -f1`  

    # Max IP suffix for the all hosts
    # Obs: all hosts = valid + reserved
    TOTAL_HOSTS=`$ECHO "$FIRST_IP_SUFFIX + $HOSTS_NAMES_NUMBER - 1" | $BC` 

    #
    # Checking if there are enough hostnames in the file
    #
    if [ $NUMBER -gt $HOSTS_NAMES_NUMBER ] ; then
	$ECHO "You need to have $NUMBER hosts for host type $hosttype,"
	$ECHO "but you don't have enough hostnames in the $FILE file."
	$ECHO "Aborting."
	exit 2
    fi

    # Check if the number of the required valid hosts is greater than 255
    if [ $MAX_NUMBER -ge 255 ] ; then
	$ECHO "The first IP ($IP_PREFIX.$FIRST_IP_SUFFIX) plus the number of the hosts required ($NUMBER)"
	$ECHO "exceeded the 255 upper limit."
	$ECHO "Solve this problem and run this script again."
	$ECHO "Aborting."
	exit 3
    fi
    
    # Check if the number of hosts, including valid and reserved ones, is greater than 255
    if [ $TOTAL_HOSTS -ge 255 ] ; then
	$ECHO "The first IP ($IP_PREFIX.$FIRST_IP_SUFFIX) plus the number of hostnames included"
	$ECHO "in the $FILE file ($HOSTS_NAMES_NUMBER) exceeded the 255 upper limit."
	$ECHO "Solve this problem and run this script again."
	exit 5
    fi

    # Looking for IP range conflicts
    for (( hosttype_index_aux=(hosttype_index+1); hosttype_index_aux < HOSTS_TYPES_NUMBER ; hosttype_index_aux++)) ; do
	hosttype_aux=${HOSTS_TYPES[$hosttype_index_aux]}
	eval FILE_AUX=\$${hosttype_aux}_FILE
	eval FIRST_IP_SUFFIX_AUX=\$${hosttype_aux}_FIRST_IP_SUFFIX
	eval NUMBER_AUX=\$${hosttype_aux}_NUMBER

        # Max IP suffix for the valid hosts
	MAX_NUMBER_AUX=`$ECHO "$FIRST_IP_SUFFIX_AUX + $NUMBER_AUX - 1" | $BC`

	# Hosts names (without comments and blank lines)
	HOSTS_NAMES_AUX=`$GREP -v '^ *#.*' $FILE_AUX | $GREP -v '^ *$'`  

 	# Number of hosts in the file without comments and blank lines
	HOSTS_NAMES_NUMBER_AUX=`$ECHO $HOSTS_NAMES_AUX | $WC -w | $CUT -d" " -f1`

        # Max IP suffix for the all hosts
        # PS: all hosts = valid + reserved
	TOTAL_HOSTS_AUX=`$ECHO "$FIRST_IP_SUFFIX_AUX + $HOSTS_NAMES_NUMBER_AUX - 1" | $BC`

	# Checking if the number of required hosts by user has conflicts
        if [ ! $MAX_NUMBER -lt $FIRST_IP_SUFFIX_AUX ] && [ ! $FIRST_IP_SUFFIX -gt $MAX_NUMBER_AUX ] ; then 
	    $ECHO "Your IP range has conflits in the $hosttype and $hosttype_aux."
	    $ECHO "Aborting."
	    exit 4
	fi

	# Checking if the number of required hosts plus reserved hosts have conflicts
	if [ ! $TOTAL_HOSTS -lt $FIRST_IP_SUFFIX_AUX ] && [ ! $FIRST_IP_SUFFIX -gt $TOTAL_HOSTS_AUX ] ; then 
	    $ECHO "Your hostnames reserved for the future have conflicts in the $hosttype and $hosttype_aux."
	    $ECHO "Check the number of the hostnames in the $FILE and $FILE_AUX files"
	    $ECHO "Aborting."
	    exit 4
	fi
    done
done
#
# ##########################################
# Printing the head section of the DNS map
# ##########################################
#  
$ECHO -e "\$TTL 86400" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "@ \t IN \t SOA  <YOUR NAME SERVER NAME>.$DOMAIN. \t root.<YOUR NAME SERVER NAME>.$DOMAIN. (" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "\t\t\t $TODAY          ; serial year-month-day-no." >> $OUTPUT_FILE_DNSMAP
$ECHO -e "\t\t\t 28800           ; refresh" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "\t\t\t 14400           ; retry" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "\t\t\t 3600000         ; expire" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "\t\t\t 86400 )         ; default_ttl" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSMAP
$ECHO -e ";; -- Name servers ---" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "@ \t\t\t IN      NS      <PUT HERE YOUR NAME SERVER NAME>" >> $OUTPUT_FILE_DNSMAP
$ECHO -e ";; Uncomment the next line to insert another server name" >> $OUTPUT_FILE_DNSMAP
$ECHO -e ";; @ \t\t\t IN      NS      <PUT HERE YOUR SLAVE SERVER NAME>" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSMAP
$ECHO -e ";; -- Email servers ---" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "@ \t\t\t IN      MX      5       <PUT HERE YOUR EMAIL SERVER NAME>" >> $OUTPUT_FILE_DNSMAP
$ECHO -e ";; Uncomment the next line to insert another email server" >> $OUTPUT_FILE_DNSMAP
$ECHO -e ";; @ \t\t\t IN      MX      10       <PUT HERE YOUR EMAIL SERVER NAME>" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSMAP
#
# ###########################
# Generating DNS map entries
# ###########################
#
for (( hosttype_index=0; hosttype_index < HOSTS_TYPES_NUMBER; hosttype_index++ )) ; do
    type=${HOSTS_TYPES[$hosttype_index]}
    eval FILE=\$${type}_FILE
    eval FIRST_IP_SUFFIX=\$${type}_FIRST_IP_SUFFIX
    eval NUMBER=\$${type}_NUMBER
    MAX_NUMBER=`$ECHO "$FIRST_IP_SUFFIX + $NUMBER - 1" | $BC`
    #
    $ECHO ";; -------------------------------" >> $OUTPUT_FILE_DNSMAP
    $ECHO ";; $type session" >> $OUTPUT_FILE_DNSMAP
    $ECHO ";; -------------------------------" >> $OUTPUT_FILE_DNSMAP

    # Don't worry about comments and blank lines in the hostname files
    HOSTS=`$GREP -v '^ *#.*' $FILE | $GREP -v '^ *$'`

    COUNT=$FIRST_IP_SUFFIX
    for host in $HOSTS ; do
        if [ $COUNT -gt $MAX_NUMBER ] ; then 	    
	    $ECHO -n ";; Reserved: " >> $OUTPUT_FILE_DNSMAP
	fi
	$ECHO -e "$host\t\tIN \t\t A \t$IP_PREFIX.$COUNT" >> $OUTPUT_FILE_DNSMAP
	COUNT=`echo "$COUNT + 1" | bc`
    done
    $ECHO ""
done
#
# #################################################
# Printing the head section of the reverse DNS map
# #################################################
#
$ECHO -e "\$TTL 86400" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "$OCT_3.$OCT_2.$OCT_1.in-addr.arpa. IN SOA <YOUR NAME SERVER NAME>.$DOMAIN.\troot.<YOUR NAME SERVER NAME>.$DOMAIN. (" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "\t\t\t $TODAY    ; serial year-month-day-no." >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "\t\t\t 28800     ; refresh" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "\t\t\t 14400     ; retry" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "\t\t\t 3600000   ; expire" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "\t\t\t 86400 )   ; default_ttl" >> $OUTPUT_FILE_DNSREVMAP
#
$ECHO -e ";; -- Name servers ---" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "@ \t\t\t IN      NS      <PUT HERE YOUR NAME SERVER NAME>.$DOMAIN." >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e ";; Uncomment the next line to insert another server name" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e ";; @ \t\t\t IN      NS      <PUT HERE YOUR SLAVE SERVER NAME>.$DOMAIN." >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSREVMAP
$ECHO -e "" >> $OUTPUT_FILE_DNSREVMAP
#
# #######################################
# Generating the reverse DNS map entries
# #######################################
#
for (( hosttype_index=0; hosttype_index < HOSTS_TYPES_NUMBER; hosttype_index++ )) ; do
    type=${HOSTS_TYPES[$hosttype_index]}
    eval FILE=\$${type}_FILE
    eval FIRST_IP_SUFFIX=\$${type}_FIRST_IP_SUFFIX
    eval NUMBER=\$${type}_NUMBER
    MAX_NUMBER=`$ECHO "$FIRST_IP_SUFFIX + $NUMBER - 1" | $BC`
    #
    $ECHO ";; -------------------------------"     >> $OUTPUT_FILE_DNSREVMAP
    $ECHO ";; $type session"                       >> $OUTPUT_FILE_DNSREVMAP
    $ECHO ";; -------------------------------"     >> $OUTPUT_FILE_DNSREVMAP

    # Don't worry about comments and blank lines in the host name files
    HOSTS=`$GREP -v '^ *#.*' $FILE | $GREP -v '^ *$'`

    COUNT=$FIRST_IP_SUFFIX
    for host in $HOSTS ; do
        if [ $COUNT -gt $MAX_NUMBER ] ; then 	    
	    $ECHO -n ";; Reserved: " >> $OUTPUT_FILE_DNSREVMAP
	fi
	$ECHO -e "$COUNT.$OCT_3.$OCT_2.$OCT_1.in-addr.arpa.\t\tIN\t\tPTR\t$host.$DOMAIN." >> $OUTPUT_FILE_DNSREVMAP
	COUNT=`echo "$COUNT + 1" | bc`
    done
    $ECHO ""
done
#
# ###################################
# Generating the named.conf section
# ###################################
#
$ECHO "zone \"$DOMAIN\" {"       > $OUTPUT_FILE_NAMEDCONF
$ECHO -e "\t type master;"      >> $OUTPUT_FILE_NAMEDCONF
$ECHO -e "\t file db.$DOMAIN;"  >> $OUTPUT_FILE_NAMEDCONF
$ECHO "};"                      >> $OUTPUT_FILE_NAMEDCONF
#
exit 0
